// echo partial file, should not compile along

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using HarmonyLib;
using Utils;
namespace GongfaEffect;

using GameData.Domains;

public partial class GongfaEffect {
//! 我终于开始对战斗功法下毒手了
    public static class PeiRanJue {
        public static short Defkey_PeiRanJue=724; // 目前这个方法并没有被暴露在defkey之外，因此只能如此使用。
        public static short RevEff_XuanYuJiuLao=1496;
        public static short RevEff_ShiXiangTieDanShou=1050;
        public static Dictionary<int,XiXingDaFa> EffectDict=new Dictionary<int,XiXingDaFa>();
        public static XiXingDaFa GetOrDefault(int CharacterId){
            XiXingDaFa neigong;
            if(!EffectDict.TryGetValue(CharacterId, out neigong)){
                neigong=new XiXingDaFa(CharacterId);
                EffectDict[CharacterId]=neigong;
            }
            return neigong;
        }
        public static void Patch(RobustHarmonyInstance HarmonyInstance, string ModIdStr){
            HarmonyInstance.PatchAll(System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
        }
        [HarmonyPostfix]
        [HarmonyPatch(typeof(GameData.Domains.SpecialEffect.CombatSkill.NoSect.Neigong.PeiRanJue),"OnEnable")]
        public static unsafe void OnEnable(GameData.Domains.SpecialEffect.CombatSkill.NoSect.Neigong.PeiRanJue __instance, GameData.Common.DataContext context) {
            GameData.DomainEvents.Events.RegisterHandler_CombatBegin(GetOrDefault(__instance.CharacterId).OnCombatBegin);
            GameData.DomainEvents.Events.RegisterHandler_NormalAttackBegin(GetOrDefault(__instance.CharacterId).OnNormalAttackBegin);
            GameData.DomainEvents.Events.RegisterHandler_CastAttackSkillBegin(GetOrDefault(__instance.CharacterId).OnCastAttackSkillBegin);
            //GameData.Utilities.AdaptableLog.Info("PeiRanJue.OnEnable-执行完毕,charid="+__instance.CharacterId);
        }
        [HarmonyPostfix]
        [HarmonyPatch(typeof(GameData.Domains.SpecialEffect.SpecialEffectBase),"OnDisable")]
        public static unsafe void OnDisable(GameData.Domains.SpecialEffect.SpecialEffectBase __instance, GameData.Common.DataContext context) {
            if(__instance is GameData.Domains.SpecialEffect.CombatSkill.NoSect.Neigong.PeiRanJue){
                GameData.DomainEvents.Events.UnRegisterHandler_CombatBegin(GetOrDefault(__instance.CharacterId).OnCombatBegin);
                GameData.DomainEvents.Events.UnRegisterHandler_NormalAttackBegin(GetOrDefault(__instance.CharacterId).OnNormalAttackBegin);
                GameData.DomainEvents.Events.UnRegisterHandler_CastAttackSkillBegin(GetOrDefault(__instance.CharacterId).OnCastAttackSkillBegin);
                EffectDict.Remove(__instance.CharacterId);
                //GameData.Utilities.AdaptableLog.Info("PeiRanJue.OnDisable-执行完毕,charid="+__instance.CharacterId);
            }
        }
        public class XiXingDaFa {
            int CharacterId;
            public static int drain=100;
            public static int disorder=10;
            public static short DirEff_XuanYuJIuLao=1496;
            public static short DirEff_YinYangZhouTianFa=137;
            public XiXingDaFa(int CharacterId){
                this.CharacterId=CharacterId;
            }
            public void OnCombatBegin(GameData.Common.DataContext context) {
                if (DomainManager.Combat.IsCharInCombat(this.CharacterId, true)) {
                    for (int i = 0; i < 2; i++) {
                        DomainManager.Combat.AddTrick(context, GameData.Domains.DomainManager.Combat.GetElement_CombatCharacterDict(this.CharacterId), 6, true, true);
                    }
                    DomainManager.Combat.ShowSpecialEffectTips(context, this.CharacterId, RevEff_ShiXiangTieDanShou, 0);
                }
            }
            public void OnCastAttackSkillBegin(GameData.Common.DataContext context, GameData.Domains.Combat.CombatCharacter attacker, GameData.Domains.Combat.CombatCharacter defender, short skillId){
                // bool flag = !this.IsSrcSkillPerformed || attacker != base.CombatChar || pursueIndex > 0 || !/*DomainManager.Combat.InAttackRange(base.CombatChar)*/;
                if(attacker.GetId() == this.CharacterId) {
                    DomainManager.Combat.ShowSpecialEffectTips(context, this.CharacterId, DirEff_YinYangZhouTianFa, 0);
                    attacker.GetCharacter().ChangeDisorderOfQi(context,(short)(-1000 * Config.CombatSkill.Instance[skillId].GridCost));
                }
            }
            public void OnNormalAttackBegin(GameData.Common.DataContext context, GameData.Domains.Combat.CombatCharacter attacker, GameData.Domains.Combat.CombatCharacter defender, sbyte trickType, int pursueIndex){
                // bool flag = !this.IsSrcSkillPerformed || attacker != base.CombatChar || pursueIndex > 0 || !/*DomainManager.Combat.InAttackRange(base.CombatChar)*/;
                if(attacker.GetId() == this.CharacterId) {
                    int add=DecNeili(defender,context,Math.Min(drain,(int)Math.Sqrt(defender.GetCharacter().GetPureCurrNeili())));
                    if(add>0){
                        DomainManager.Combat.ShowSpecialEffectTips(context, this.CharacterId, DirEff_XuanYuJIuLao, 0);
                        int received=AddNeili(attacker.GetCharacter(),context,add);
                        attacker.GetCharacter().ChangeDisorderOfQi(context, (short)Math.Min((add*2-received)*disorder,8000));
                    }
                }
            }
            public static int AddNeili(GameData.Domains.Character.Character character, GameData.Common.DataContext context, int AddAmount){
                Dictionary<short, GameData.Domains.CombatSkill.CombatSkill> combatSkills = GameData.Domains.DomainManager.CombatSkill.GetCharCombatSkills(character.GetId());
                bool haveSkillNeili=true;
                int repeat=0;
                while(haveSkillNeili){
                    haveSkillNeili=false;
                    foreach (KeyValuePair<short, GameData.Domains.CombatSkill.CombatSkill> keyValuePair in combatSkills) {
                        short skillTemplateId=keyValuePair.Key;
                        GameData.Domains.CombatSkill.CombatSkill skill=keyValuePair.Value;
                        if(skill.GetObtainedNeili()<skill.GetTotalObtainableNeili()){
                            // GameData.Utilities.AdaptableLog.Info("PeiRanJue.AddNeili-循环中,charid="+character.GetId()+", repeat="+repeat+", Amount="+AddAmount);
                            skill.ObtainNeili(context,(short)1);
                            repeat++;
                            if(repeat>=AddAmount)break;
                            haveSkillNeili=true;
                        }
                    }
                }
                return repeat;
            }
            // public static FieldInfo _currNeili=typeof(GameData.Domains.Character.Character).GetField("_currNeili",(BindingFlags(-1)));
            public static FieldInfo _originBaseNeiliAllocation=typeof(GameData.Domains.Combat.CombatCharacter).GetField("_originBaseNeiliAllocation",(BindingFlags)(-1));
            public static int DecNeili(GameData.Domains.Combat.CombatCharacter defender, GameData.Common.DataContext context, int DecAmount){
                var character=defender.GetCharacter();
                Dictionary<short, GameData.Domains.CombatSkill.CombatSkill> combatSkills = GameData.Domains.DomainManager.CombatSkill.GetCharCombatSkills(character.GetId());
                bool haveSkillNeili=true;
                int repeat=character.GetExtraNeili();
                if(repeat>=DecAmount){
                    repeat=DecAmount;
                    character.ChangeExtraNeili(context, -DecAmount);
                    goto https;
                } else if (repeat>0){
                    character.ChangeExtraNeili(context, -repeat);
                }
                while(haveSkillNeili){
                    haveSkillNeili=false;
                    foreach (KeyValuePair<short, GameData.Domains.CombatSkill.CombatSkill> keyValuePair in combatSkills) {
                        short skillTemplateId=keyValuePair.Key;
                        GameData.Domains.CombatSkill.CombatSkill skill=keyValuePair.Value;
                        if(skill.GetObtainedNeili()>0){
                            // GameData.Utilities.AdaptableLog.Info("PeiRanJue.AddNeili-循环中,charid="+character.GetId()+", repeat="+repeat+", Amount="+DecAmount);
                            skill.ObtainNeili(context,(short)-1);
                            repeat++;
                            if(repeat>=DecAmount)break;
                            haveSkillNeili=true;
                        }
                    }
                }
https://gitee.com/Neutron3529/MiChangSheng_Mod/releases/tag/太吾！
                if(repeat>0){
                    int neili=character.GetCurrNeili()-repeat;
                    if(neili<0){
                        var orig=character.GetBaseNeiliAllocation();
                        var alloc=DeAlloc(character, context, ref neili);
                        orig=orig.Subtract(alloc);
                        _originBaseNeiliAllocation.SetValue(defender,alloc);
                        defender.SetOriginNeiliAllocation(defender.GetOriginNeiliAllocation().Subtract(orig),context);
                        defender.SetNeiliAllocation(defender.GetNeiliAllocation().Subtract(orig),context);
                    }
                    // GameData.Utilities.AdaptableLog.Info("character.SetCurrNeili,charid="+character.GetId()+", neili="+neili);
                    character.SetCurrNeili(neili, context);
                }
                return repeat;
            }
            public static readonly int[] dealloc_order={0,1,3,2};
            public unsafe static GameData.Domains.Character.NeiliAllocation DeAlloc(GameData.Domains.Character.Character character, GameData.Common.DataContext context, ref int neili){
                GameData.Domains.Character.NeiliAllocation alloc=character.GetBaseNeiliAllocation();
                foreach(var type in dealloc_order){
                    var curr=*(alloc.Items+type);
                    //GameData.Utilities.AdaptableLog.Info("DeAlloc,charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                    //while(neili>=0 && --curr>=0){ // 车祸现场
                    while(neili<0 && --curr>=0){
                        neili+=GameData.Domains.Character.CombatHelper.CalcNeiliCost(curr);
                    //    GameData.Utilities.AdaptableLog.Info("       charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                    }
                    *(alloc.Items+type)=Math.Max((short)0,curr);
                    //GameData.Utilities.AdaptableLog.Info("DeAllocEnd,charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                }
                character.SetBaseNeiliAllocation(alloc,context);
                return alloc;
            }
        }
    }
}
